home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Source Code
/
Libraries
/
Apache 1.0
/
src
/
mod_include.c
< prev
next >
Wrap
Text File
|
1995-12-04
|
26KB
|
874 lines
/* ====================================================================
* Copyright (c) 1995 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 5. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
/*
* http_include.c: Handles the server-parsed HTML documents
*
* Original by Rob McCool; substantial fixups by David Robinson;
* incorporated into the Shambhala module framework by rst.
*
*/
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_log.h"
#include "http_main.h"
#include "util_script.h"
#define STARTING_SEQUENCE "<!--#"
#define ENDING_SEQUENCE "-->"
#define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
#define DEFAULT_TIME_FORMAT "%A, %d-%b-%y %T %Z"
#define SIZEFMT_BYTES 0
#define SIZEFMT_KMG 1
static void decodehtml(char *s);
static char *get_tag(pool *p, FILE *in, char *tag, int tag_len, int dodecode);
static int get_directive(FILE *in, char *d);
/* ------------------------ Environment function -------------------------- */
void add_include_vars(request_rec *r, char *timefmt)
{
table *e = r->subprocess_env;
char *t;
time_t date = time(NULL);
table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
table_set(e, "LAST_MODIFIED",ht_time(r->pool,r->finfo.st_mtime,timefmt,0));
table_set(e, "DOCUMENT_URI", r->uri);
table_set(e, "DOCUMENT_PATH_INFO", r->path_info);
if((t = strrchr(r->filename, '/')))
table_set (e, "DOCUMENT_NAME", ++t);
else
table_set (e, "DOCUMENT_NAME", r->uri);
}
#define GET_CHAR(f,c,r) \
{ \
int i = getc(f); \
if(feof(f) || ferror(f) || (i == -1)) { \
fclose(f); \
return r; \
} \
c = (char)i; \
}
/* --------------------------- Parser functions --------------------------- */
/* Grrrr... rputc makes this slow as all-get-out. Elsewhere, it doesn't
* matter much, but this is an inner loop...
*/
int find_string(FILE *in,char *str, request_rec *r) {
int x,l=strlen(str),p;
char c;
p=0;
while(1) {
GET_CHAR(in,c,1);
if(c == str[p]) {
if((++p) == l)
return 0;
}
else {
if(r) {
if(p) {
for(x=0;x<p;x++) {
rputc(str[x],r);
}
}
rputc(c,r);
}
p=0;
}
}
}
/*
* decodes a string containing html entities or numeric character references.
* 's' is overwritten with the decoded string.
* If 's' is syntatically incorrect, then the followed fixups will be made:
* unknown entities will be left undecoded;
* references to unused numeric characters will be deleted.
* In particular, will not be decoded, but will be deleted.
*
* drtr
*/
/* maximum length of any ISO-LATIN-1 HTML entity name. */
#define MAXENTLEN (6)
/* The following is a shrinking transformation, therefore safe. */
static void
decodehtml(char *s)
{
int val, i, j;
char *p=s;
char *ents;
static char *entlist[MAXENTLEN+1]={
NULL, /* 0 */
NULL, /* 1 */
"lt\074gt\076", /* 2 */
"amp\046ETH\320eth\360", /* 3 */
"quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\
iuml\357ouml\366uuml\374yuml\377", /* 4 */
"Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\
THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352icirc\356ocirc\364\
ucirc\373thorn\376", /* 5 */
"Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\
Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde\325Oslash\330\
Ugrave\331Uacute\332Yacute\335agrave\340aacute\341atilde\343ccedil\347\
egrave\350eacute\351igrave\354iacute\355ntilde\361ograve\362oacute\363\
otilde\365oslash\370ugrave\371uacute\372yacute\375" /* 6 */
};
for (; *s != '\0'; s++, p++) {
if (*s != '&') {
*p = *s;
continue;
}
/* find end of entity */
for (i=1; s[i] != ';' && s[i] != '\0'; i++)
continue;
if (s[i] == '\0') { /* treat as normal data */
*p = *s;
continue;
}
/* is it numeric ? */
if (s[1] == '#') {
for (j=2, val=0; j < i && isdigit(s[j]); j++)
val = val * 10 + s[j] - '0';
s += i;
if (j < i || val <= 8 || (val >= 11 && val <= 31) ||
(val >= 127 && val <= 160) || val >= 256)
p--; /* no data to output */
else
*p = val;
} else{
j = i-1;
if (i-1 > MAXENTLEN || entlist[i-1] == NULL) { /* wrong length */
*p = '&';
continue; /* skip it */
}
for (ents=entlist[i-1]; *ents != '\0'; ents += i)
if (strncmp(s+1, ents, i-1) == 0) break;
if (*ents == '\0')
*p = '&'; /* unknown */
else {
*p = ((const unsigned char *)ents)[i-1];
s += i;
}
}
}
*p = '\0';
}
/*
* extract the next tag name and value.
* if there are no more tags, set the tag name to 'done'
* the tag value is html decoded if dodecode is non-zero
*/
static char *
get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode) {
char *t = tag, *tag_val, c, term;
int n;
n = 0;
do { /* skip whitespace */
GET_CHAR(in,c,NULL);
} while (isspace(c));
/* tags can't start with - */
if(c == '-') {
GET_CHAR(in,c,NULL);
if(c == '-') {
do {
GET_CHAR(in,c,NULL);
} while (isspace(c));
if(c == '>') {
strcpy(tag,"done");
return tag;
}
}
return NULL; /* failed */
}
/* find end of tag name */
while(1) {
if(++n == tagbuf_len) {
t[tagbuf_len - 1] = '\0';
return NULL;
}
if(c == '=' || isspace(c)) break;
*(t++) = tolower(c);
GET_CHAR(in,c,NULL);
}
*t++ = '\0';
tag_val = t;
while (isspace(c)) GET_CHAR(in, c, NULL); /* space before = */
if (c != '=') return NULL;
do {
GET_CHAR(in,c,NULL); /* space after = */
} while (isspace(c));
/* we should allow a 'name' as a value */
if (c != '"' && c != '\'') return NULL;
term = c;
while(1) {
GET_CHAR(in,c,NULL);
if(++n == tagbuf_len) {
t[tagbuf_len - 1] = '\0';
return NULL;
}
if (c == term) break;
*(t++) = c;
}
*t = '\0';
if (dodecode) decodehtml(tag_val);
return pstrdup (p, tag_val);
}
static int
get_directive(FILE *in, char *d) {
char c;
/* skip initial whitespace */
while(1) {
GET_CHAR(in,c,1);
if(!isspace(c))
break;
}
/* now get directive */
while(1) {
*d++ = tolower(c);
GET_CHAR(in,c,1);
if(isspace(c))
break;
}
*d = '\0';
return 0;
}
/* --------------------------- Action handlers ---------------------------- */
int include_cgi(char *s, request_rec *r)
{
request_rec *rr = sub_req_lookup_uri (s, r);
if (rr->status != 200) return -1;
/* No hardwired path info or query allowed */
if ((rr->path_info && rr->path_info[0]) || rr->args) return -1;
if (rr->finfo.st_mode == 0) return -1;
/* Script gets parameters of the *document*, for back compatibility */
rr->path_info = r->path_info; /* painful to get right; see mod_cgi.c */
rr->args = r->args;
/* Force sub_req to be treated as a CGI request, even if ordinary
* typing rules would have called it something else.
*/
rr->content_type = CGI_MAGIC_TYPE;
/* Run it. */
if (run_sub_req (rr) == REDIRECT) {
char *location = table_get (rr->headers_out, "Location");
rprintf(r,"<A HREF=\"%s\">%s</A>",location,location);
}
destroy_sub_req (rr);
return 0;
}
int handle_include(FILE *in, request_rec *r, char *error, int noexec) {
char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN];
char *tag_val;
while(1) {
if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
if(!strcmp(tag,"file") || !strcmp (tag, "virtual")) {
request_rec *rr=NULL;
char *error_fmt = NULL;
if (tag[0] == 'f')
{ /* be safe; only files in this directory or below allowed */
char tmp[MAX_STRING_LEN+2];
sprintf(tmp, "/%s/", tag_val);
if (tag_val[0] == '/' || strstr(tmp, "/../") != NULL)
error_fmt = "unable to include file %s in parsed file %s";
else
rr = sub_req_lookup_file (tag_val, r);
} else
rr = sub_req_lookup_uri (tag_val, r);
if (!error_fmt && rr->status != 200)
error_fmt = "unable to include %s in parsed file %s";
if (!error_fmt && noexec && rr->content_type
&& (strncmp (rr->content_type, "text/", 5)))
error_fmt =
"unable to include potential exec %s in parsed file %s";
if (!error_fmt && run_sub_req (rr))
error_fmt = "unable to include %s in parsed file %s";
if (error_fmt) {
sprintf(errstr, error_fmt, tag_val, r->filename);
log_error (errstr, r->server);
rprintf(r,"%s",error);
}
if (rr != NULL) destroy_sub_req (rr);
}
else if(!strcmp(tag,"done"))
return 0;
else {
sprintf(errstr,"unknown parameter %s to tag include in %s",tag,
r->filename);
log_error (errstr, r->server);
rprintf(r,"%s",error);
}
}
}
typedef struct {
request_rec *r;
char *s;
} include_cmd_arg;
void include_cmd_child (void *arg)
{
request_rec *r = ((include_cmd_arg *)arg)->r;
char *s = ((include_cmd_arg *)arg)->s;
table *env = r->subprocess_env;
#ifdef DEBUG_INCLUDE_CMD
FILE *dbg = fopen ("/dev/tty", "w");
#endif
char err_string [MAX_STRING_LEN];
#ifdef DEBUG_INCLUDE_CMD
fprintf (dbg, "Attempting to include command '%s'\n", s);
#endif
if (r->path_info && r->path_info[0] != '\0')
{
request_rec *pa_req;
table_set (env, "PATH_INFO", escape_shell_cmd (r->pool, r->path_info));
pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r);
if (pa_req->filename)
table_set(env, "PATH_TRANSLATED",
pstrcat(r->pool, pa_req->filename, pa_req->path_info,
NULL));
}
if (r->args) {
table_set (env, "QUERY_STRING", r->args);
unescape_url (r->args);
table_set (env, "QUERY_STRING_UNESCAPED",
escape_shell_cmd (r->pool, r->args));
}
error_log2stderr (r->server);
#ifdef DEBUG_INCLUDE_CMD
fprintf (dbg, "Attempting to exec '%s'\n", s);
#endif
cleanup_for_exec();
execle(SHELL_PATH, SHELL_PATH, "-c", s, NULL,
create_environment (r->pool, env));
/* Oh, drat. We're still here. The log file descriptors are closed,
* so we have to whimper a complaint onto stderr...
*/
#ifdef DEBUG_INCLUDE_CMD
fprintf (dbg, "Exec failed\n");
#endif
sprintf(err_string, "httpd: exec of %s failed, errno is %d\n",
SHELL_PATH,errno);
write (2, err_string, strlen(err_string));
exit(0);
}
int include_cmd(char *s, request_rec *r) {
include_cmd_arg arg;
FILE *f;
arg.r = r; arg.s = s;
if (!spawn_child (r->connection->pool, include_cmd_child, &arg,
kill_after_timeout, NULL, &f))
return -1;
send_fd(f,r);
pfclose(r->pool, f); /* will wait for zombie when
* r->pool is cleared
*/
return 0;
}
int handle_exec(FILE *in, request_rec *r, char *error)
{
char tag[MAX_STRING_LEN],errstr[MAX_STRING_LEN];
char *tag_val;
char *file = r->filename;
while(1) {
if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
if(!strcmp(tag,"cmd")) {
if(include_cmd(tag_val, r) == -1) {
sprintf(errstr,"failed command exec %s in %s",tag_val,file);
log_error (errstr, r->server);
rprintf(r,"%s",error);
}
/* just in case some stooge changed directories */
chdir_file(r->filename);
}
else if(!strcmp(tag,"cgi")) {
if(include_cgi(tag_val, r) == -1) {
sprintf(errstr,"invalid CGI ref %s in %s",tag_val,file);
log_error (errstr, r->server);
rprintf(r,"%s",error);
}
/* grumble groan */
chdir_file(r->filename);
}
else if(!strcmp(tag,"done"))
return 0;
else {
char errstr[MAX_STRING_LEN];
sprintf(errstr,"unknown parameter %s to tag exec in %s",tag,file);
log_error (errstr, r->server);
rprintf(r, "%s",error);
}
}
}
int handle_echo (FILE *in, request_rec *r, char *error) {
char tag[MAX_STRING_LEN];
char *tag_val;
while(1) {
if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
if(!strcmp(tag,"var")) {
char *val = table_get (r->subprocess_env, tag_val);
if (val) rprintf (r, "%s", val);
else rprintf (r, "(none)");
} else if(!strcmp(tag,"done"))
return 0;
else {
char errstr[MAX_STRING_LEN];
sprintf(errstr,"unknown parameter %s to tag echo in %s",
tag, r->filename);
log_error(errstr, r->server);
rprintf (r, "%s", error);
}
}
}
int handle_config(FILE *in, request_rec *r, char *error, char *tf,
int *sizefmt) {
char tag[MAX_STRING_LEN];
char *tag_val;
table *env = r->subprocess_env;
while(1) {
if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0)))
return 1;
if(!strcmp(tag,"errmsg"))
strcpy(error,tag_val);
else if(!strcmp(tag,"timefmt")) {
time_t date = time(NULL);
strcpy(tf,tag_val);
table_set (env, "DATE_LOCAL", ht_time(r->pool,date,tf,0));
table_set (env, "DATE_GMT", ht_time(r->pool,date,tf,1));
table_set (env, "LAST_MODIFIED", ht_time(r->pool,r->finfo.st_mtime,tf,0));
}
else if(!strcmp(tag,"sizefmt")) {
decodehtml(tag_val);
if(!strcmp(tag_val,"bytes"))
*sizefmt = SIZEFMT_BYTES;
else if(!strcmp(tag_val,"abbrev"))
*sizefmt = SIZEFMT_KMG;
}
else if(!strcmp(tag,"done"))
return 0;
else {
char errstr[MAX_STRING_LEN];
sprintf(errstr,"unknown parameter %s to tag config in %s",
tag, r->filename);
log_error(errstr, r->server);
rprintf (r,"%s",error);
}
}
}
int find_file(request_rec *r, char *directive, char *tag,
char *tag_val, struct stat *finfo, char *error)
{
char errstr[MAX_STRING_LEN], dir[MAX_STRING_LEN];
char *to_send;
if(!strcmp(tag,"file")) {
getparents(tag_val); /* get rid of any nasties */
getwd(dir);
to_send = make_full_path (r->pool, dir, tag_val);
if(stat(to_send,finfo) == -1) {
sprintf(errstr,
"unable to get information about %s in parsed file %s",
to_send, r->filename);
log_error (errstr, r->server);
rprintf (r,"%s",error);
return -1;
}
return 0;
}
else if(!strcmp(tag,"virtual")) {
request_rec *rr = sub_req_lookup_uri (tag_val, r);
if (rr->status == 200 && rr->finfo.st_mode != 0) {
memcpy ((char*)finfo, (const char *)&rr->finfo, sizeof (struct stat));
destroy_sub_req (rr);
return 0;
} else {
sprintf(errstr,
"unable to get information about %s in parsed file %s",
tag_val, r->filename);
log_error(errstr, r->server);
rprintf(r,"%s",error);
destroy_sub_req (rr);
return -1;
}
}
else {
sprintf(errstr,"unknown parameter %s to tag %s in %s",
tag, directive, r->filename);
log_error(errstr, r->server);
rprintf(r,"%s",error);
return -1;
}
}
int handle_fsize(FILE *in, request_rec *r, char *error, int sizefmt)
{
char tag[MAX_STRING_LEN];
char *tag_val;
struct stat finfo;
while(1) {
if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
else if(!strcmp(tag,"done"))
return 0;
else if(!find_file(r,"fsize",tag,tag_val,&finfo,error)) {
if(sizefmt == SIZEFMT_KMG) {
send_size(finfo.st_size, r);
}
else {
int l,x;
#if defined(BSD) && BSD > 199305
sprintf(tag,"%qd",finfo.st_size);
#else
sprintf(tag,"%ld",finfo.st_size);
#endif
l = strlen(tag); /* grrr */
for(x=0;x<l;x++) {
if(x && (!((l-x) % 3))) {
rputc(',', r);
}
rputc (tag[x],r);
}
}
}
}
}
int handle_flastmod(FILE *in, request_rec *r, char *error, char *tf)
{
char tag[MAX_STRING_LEN];
char *tag_val;
struct stat finfo;
while(1) {
if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
else if(!strcmp(tag,"done"))
return 0;
else if(!find_file(r,"flastmod",tag,tag_val,&finfo,error))
rprintf (r, "%s", ht_time(r->pool, finfo.st_mtime, tf, 0));
}
}
/* -------------------------- The main function --------------------------- */
/* This is a stub which parses a file descriptor. */
void send_parsed_content(FILE *f, request_rec *r)
{
char directive[MAX_STRING_LEN], error[MAX_STRING_LEN];
char timefmt[MAX_STRING_LEN], errstr[MAX_STRING_LEN];
int noexec = allow_options (r) & OPT_INCNOEXEC;
int ret, sizefmt;
strcpy(error,DEFAULT_ERROR_MSG);
strcpy(timefmt,DEFAULT_TIME_FORMAT);
sizefmt = SIZEFMT_KMG;
chdir_file (r->filename);
while(1) {
if(!find_string(f,STARTING_SEQUENCE,r)) {
if(get_directive(f,directive))
return;
if(!strcmp(directive,"exec")) {
if(noexec) {
sprintf(errstr,"httpd: exec used but not allowed in %s",
r->filename);
log_error (errstr, r->server);
rprintf(r,"%s",error);
ret = find_string(f,ENDING_SEQUENCE,NULL);
} else
ret=handle_exec(f, r, error);
}
else if(!strcmp(directive,"config"))
ret=handle_config(f, r, error, timefmt, &sizefmt);
else if(!strcmp(directive,"include"))
ret=handle_include(f, r, error, noexec);
else if(!strcmp(directive,"echo"))
ret=handle_echo(f, r, error);
else if(!strcmp(directive,"fsize"))
ret=handle_fsize(f, r, error, sizefmt);
else if(!strcmp(directive,"flastmod"))
ret=handle_flastmod(f, r, error, timefmt);
else {
sprintf(errstr,"httpd: unknown directive %s in parsed doc %s",
directive,r->filename);
log_error (errstr, r->server);
rprintf (r,"%s",error);
ret=find_string(f,ENDING_SEQUENCE,NULL);
}
if(ret) {
sprintf(errstr,"httpd: premature EOF in parsed file %s",
r->filename);
log_error(errstr, r->server);
return;
}
} else
return;
}
}
/*****************************************************************
*
* XBITHACK. Sigh... NB it's configurable per-directory; the compile-time
* option only changes the default.
*/
module includes_module;
enum xbithack { xbithack_off, xbithack_on, xbithack_full };
#ifdef XBITHACK
#define DEFAULT_XBITHACK xbithack_full
#else
#define DEFAULT_XBITHACK xbithack_off
#endif
void *create_includes_dir_config (pool *p, char *dummy)
{
enum xbithack *result = (enum xbithack*)palloc(p, sizeof (enum xbithack));
*result = DEFAULT_XBITHACK;
return result;
}
char *set_xbithack (cmd_parms *cmd, void *xbp, char *arg)
{
enum xbithack *state = (enum xbithack *)xbp;
if (!strcasecmp (arg, "off")) *state = xbithack_off;
else if (!strcasecmp (arg, "on")) *state = xbithack_on;
else if (!strcasecmp (arg, "full")) *state = xbithack_full;
else return "XBitHack must be set to Off, On, or Full";
return NULL;
}
int send_parsed_file(request_rec *r)
{
FILE *f;
enum xbithack *state =
(enum xbithack *)get_module_config(r->per_dir_config,&includes_module);
int errstatus;
if (!(allow_options (r) & OPT_INCLUDES)) return DECLINED;
if (r->method_number != M_GET) return DECLINED;
if (r->finfo.st_mode == 0) return NOT_FOUND;
if (*state == xbithack_full
&& (r->finfo.st_mode & S_IXGRP)
&& (errstatus = set_last_modified (r, r->finfo.st_mtime)))
return errstatus;
if(!(f=pfopen(r->pool, r->filename, "r"))) {
log_reason("file permissions deny server access", r->filename, r);
return FORBIDDEN;
}
r->content_type = "text/html";
hard_timeout ("send", r);
send_http_header(r);
if (r->header_only) {
kill_timeout (r);
pfclose (r->pool, f);
return OK;
}
if (r->main) {
/* Kludge --- for nested includes, we want to keep the
* subprocess environment of the base document (for compatibility);
* that means torquing our own last_modified date as well so that
* the LAST_MODIFIED variable gets reset to the proper value if
* the nested document resets <!--#config timefmt-->
*/
r->subprocess_env = r->main->subprocess_env;
r->finfo.st_mtime= r->main->finfo.st_mtime;
} else {
add_common_vars (r);
add_include_vars (r, DEFAULT_TIME_FORMAT);
}
send_parsed_content (f, r);
kill_timeout (r);
return OK;
}
int xbithack_handler (request_rec *r)
{
enum xbithack *state;
if (!(r->finfo.st_mode & S_IXUSR)) return DECLINED;
state = (enum xbithack *)get_module_config(r->per_dir_config,
&includes_module);
if (*state == xbithack_off) return DECLINED;
return send_parsed_file (r);
}
command_rec includes_cmds[] = {
{ "XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1, "Off, On, or Full" },
{ NULL }
};
handler_rec includes_handlers[] = {
{ INCLUDES_MAGIC_TYPE, send_parsed_file },
{ INCLUDES_MAGIC_TYPE3, send_parsed_file },
{ "*/*", xbithack_handler },
{ NULL }
};
module includes_module = {
STANDARD_MODULE_STUFF,
NULL, /* initializer */
create_includes_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
includes_cmds, /* command table */
includes_handlers, /* handlers */
NULL, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
NULL /* logger */
};